//
// Copyright (C) [2024] Xingyun Integrated Circuit, Inc.
//
// GreenCode was a private technology asset of Xingyun Integrated Circuit， Inc （Confidential）
//  Author: Shawn.Tan
//  Date : 2025.10.28
//
//  History : Initial Version 2025.10.28
//

//
#include "VmFactoryGPGPU.h"

#include "AddressTagging.h"
#include "Constraint.h"
#include "Generator.h"
#include "Log.h"
#include "PageTableConstraint.h"
#include "UtilityFunctions.h"
#include "VmDirectMapControlBlockGPGPU.h"
#include "VmInfoGPGPU.h"
#include "VmMapper.h"
#include "VmPaMapper.h"
#include "VmasControlBlockGPGPU.h"

using namespace std;

/*!
  \file VmFactoryGPGPU.cc
  \brief Code supporting construction of RISC-specific virtual memory management objects.
*/

namespace Green {

  VmRegime* VmFactoryGPGPU::VmRegimeInstance() const
  {
    switch (mVmRegimeType)
    {
      case EVmRegimeType::M:
        return new VmPagingRegime(this, mVmRegimeType, EPrivilegeLevelType::M, EMemBankType::Default);
      case EVmRegimeType::S:
        return new VmPagingRegime(this, mVmRegimeType, EPrivilegeLevelType::S, EMemBankType::Default);
      case EVmRegimeType::HS:
        return new VmPagingRegime(this, mVmRegimeType, EPrivilegeLevelType::S, EMemBankType::Default);
      case EVmRegimeType::VS:
        return new VmPagingRegime(this, mVmRegimeType, EPrivilegeLevelType::S, EMemBankType::Default);
      default:
        LOG(fail) << "{VmFactoryGPGPU::VmRegimeInstance} invalid regime type: " << EVmRegimeType_to_string(mVmRegimeType) << endl;
        FAIL("invalid_regime_type_vm_regime_instance");
    }

    return nullptr;
  }

  VmDirectMapControlBlock* VmFactoryGPGPU::CreateVmDirectMapControlBlock(const EMemBankType memBankType) const
  {
    switch (mVmRegimeType)
    {
      case EVmRegimeType::M:
        return new VmDirectMapControlBlockGPGPU(EPrivilegeLevelType::M, memBankType);
      case EVmRegimeType::S:
      case EVmRegimeType::HS:
      case EVmRegimeType::VS:
        return new VmDirectMapControlBlockGPGPU(EPrivilegeLevelType::S, memBankType);
      default:
        LOG(fail) << "{VmFactoryGPGPU::CreateVmDirectMapControlBlock} Unsupported EVmRegimeType enum value: " << EVmRegimeType_to_string(mVmRegimeType) << endl;
        FAIL("invalid_regime_type_vm_dmcb");
    }

    return nullptr;
  }

  VmasControlBlock* VmFactoryGPGPU::CreateVmasControlBlock(const EMemBankType memBankType) const
  {
    switch (mVmRegimeType)
    {
      case EVmRegimeType::M:
        return new VmasControlBlockGPGPU(EPrivilegeLevelType::M, memBankType);
      case EVmRegimeType::S:
      case EVmRegimeType::HS:
      case EVmRegimeType::VS:
        return new VmasControlBlockGPGPU(EPrivilegeLevelType::S, memBankType);
      default:
        LOG(fail) << "{VmFactoryGPGPU::CreateVmasControlBlock} Unsupported EVmRegimeType enum value: " << EVmRegimeType_to_string(mVmRegimeType) << endl;
        FAIL("invalid_regime_type_vmas_cb");
    }
    return nullptr;
  }


  AddressTagging* VmFactoryGPGPU::CreateAddressTagging(const VmControlBlock& rVmControlBlock) const
  {
    return new AddressTagging();
  }

  PteAttribute* VmFactoryGPGPU::PteAttributeInstance(EPteAttributeType attrType) const
  {
    LOG(fail) << "{VmFactoryGPGPU::PteAttributeInstance} not yet implemented." << endl;
    FAIL("not-yet-implemented");

    return nullptr;
  }

  void VmFactoryGPGPU::SetupVmConstraints(std::vector<ConstraintSet* >& rVmConstraints) const
  {
    check_enum_size(EVmConstraintTypeSize);
    for (EVmConstraintTypeBaseType i = 0; i < EVmConstraintTypeSize; ++ i) {
      LOG(info) << "{VmFactoryGPGPU::SetupVmConstraints} instantiating " << EVmConstraintType_to_string(EVmConstraintType(i)) << " constraint." << endl;
      rVmConstraints.push_back(new ConstraintSet());
    }
  }

  EPrivilegeLevelType VmFactoryGPGPU::GetPrivilegeLevel() const
  {
    switch (mVmRegimeType)
    {
      case EVmRegimeType::M:
        return EPrivilegeLevelType::M;
      case EVmRegimeType::S:
      case EVmRegimeType::HS:
      case EVmRegimeType::VS:
        return EPrivilegeLevelType::S;
      default:
        LOG(fail) << "{VmFactoryGPGPU::GetPrivilegeLevel} Unsupported EVmRegimeType enum value: " << EVmRegimeType_to_string(mVmRegimeType) << endl;
        FAIL("invalid_regime_type_get_priv");
    }

    return EPrivilegeLevelType::M;
  }

  void VmFactoryGPGPU::GetRegisterContext(std::vector<std::string>& rRegNames, bool pagingEnabled) const
  {
    rRegNames.push_back("mstatus");
    rRegNames.push_back("misa");
    rRegNames.push_back("privilege");

    switch (mVmRegimeType)
    {
      case EVmRegimeType::M:
        break;
      case EVmRegimeType::S:
        rRegNames.push_back("sstatus");
        if (pagingEnabled) rRegNames.push_back("satp");
        break;
      case EVmRegimeType::HS:
        break;
        //hgatp, hstatus
      case EVmRegimeType::VS:
        break;
        //vsstatus, vsatp
      default:
        LOG(fail) << "{VmFactoryGPGPU::GetRegisterContext} Unsupported EVmRegimeType enum value: " << EVmRegimeType_to_string(mVmRegimeType) << endl;
        FAIL("invalid_regime_type_get_reg_context");
    }
  }

  void VmFactoryGPGPU::GetDelayedRegisterContext(std::vector<std::string>& rRegNames) const
  {
  }

  bool VmFactoryGPGPU::PagingEnabled(Generator& rGen) const
  {
    VmInfoGPGPU vm_info;
    vm_info.SetPrivilegeLevelType(GetPrivilegeLevel());
    vm_info.GetOtherStates(rGen);
    return vm_info.PagingEnabled();
  }

  VmContext* VmFactoryGPGPU::CreateVmContext() const
  {
    LOG(fail) << "{VmFactoryGPGPU::CreateVmContext} not yet implemented." << endl;
    FAIL("not-yet-implemented");

    return nullptr;
  }

  void VmFactoryGPGPU::CreatePageTableConstraints(std::vector<PageTableConstraint* >& rPageTableConstraints) const
  {
    for (EMemBankTypeBaseType i = 0; i < EMemBankTypeSize; ++ i)
    {
      LOG(info) << "{VmFactoryGPGPU::CreatePageTableConstraints} instantiating " << EMemBankType_to_string(EMemBankType(i)) << " constraint." << endl;
      rPageTableConstraints.push_back(new PageTableConstraint(EMemBankType(i)));
    }
  }

  VmPaMapper* VmFactoryGPGPU::VmPaMapperInstance(VmAddressSpace* pAddressSpace) const
  {
    return new VmPaMapper(pAddressSpace);
  }

}
